package cn.schoolwow.quickdao.module.entity.flow.common;

import cn.schoolwow.quickdao.annotation.Ignore;
import cn.schoolwow.quickdao.domain.entity.Entity;
import cn.schoolwow.quickdao.module.entity.domain.EntityOption;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import com.alibaba.fastjson.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Stack;

public class GetEntityAllFieldsFlow implements BusinessFlow {
    private Logger logger = LoggerFactory.getLogger(GetEntityAllFieldsFlow.class);

    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        Entity entity = (Entity) flowContext.checkData("entity");

        List<Field> fieldList = new ArrayList<>();
        Class tempClass = entity.clazz;
        while (null != tempClass) {
            Field[] fields = tempClass.getDeclaredFields();
            Field.setAccessible(fields, true);
            for (Field field : fields) {
                if (Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) {
                    logger.trace("跳过常量或静态变量,该字段被static或者final修饰!字段名:{}", field.getName());
                    continue;
                }
                if (field.getDeclaredAnnotation(Ignore.class) != null) {
                    logger.trace("跳过实体属性,该属性被Ignore注解修饰!字段名:{}", field.getName());
                    continue;
                }
                //跳过List类型和数组类型
                if (field.getType().isArray() || (!field.getType().isPrimitive() && isCollection(field.getType()))) {
                    logger.trace("跳过集合类型!字段名:{}", field.getName());
                    continue;
                }
                boolean shouldIgnoreClass = (boolean) flowContext.startFlow(new ShouldIgnoreClassFlow())
                        .printTrace(false)
                        .putTemporaryData("clazz", field.getType())
                        .execute()
                        .checkData("shouldIgnoreClass");
                if (shouldIgnoreClass) {
                    logger.trace("跳过用户指定过滤条件!字段名:{}", field.getName());
                    continue;
                }
                field.setAccessible(true);
                fieldList.add(field);
            }
            tempClass = tempClass.getSuperclass();
            if (null != tempClass && "java.lang.Object".equals(tempClass.getName())) {
                break;
            }
        }
        flowContext.putTemporaryData("fieldList", fieldList);
    }

    @Override
    public String name() {
        return "获取实体类所有字段";
    }

    private boolean isCollection(Class clazz) {
        //排除JSONArray类型
        if(clazz.getName().equals(JSONArray.class.getName())){
            return false;
        }
        Stack<Class[]> stack = new Stack<>();
        stack.push(clazz.getInterfaces());
        while (!stack.isEmpty()) {
            Class[] classes = stack.pop();
            for (Class _clazz : classes) {
                if (_clazz.getName().equals(Collection.class.getName())) {
                    return true;
                }
                Class[] subClasses = _clazz.getInterfaces();
                if (null != subClasses && subClasses.length > 0) {
                    stack.push(subClasses);
                }
            }
        }
        return false;
    }

    private static boolean shouldIgnoreClass(Class clazz, EntityOption entityOption) {
        if (clazz.isEnum()) {
            return true;
        }
        if (clazz.getAnnotation(Ignore.class) != null) {
            return true;
        }

        //根据类过滤
        if (null != entityOption.ignoreClassList) {
            for (Class _clazz : entityOption.ignoreClassList) {
                if (_clazz.getName().equals(clazz.getName())) {
                    return true;
                }
            }
        }
        //根据包名过滤
        if (null != entityOption.ignorePackageNameList) {
            for (String ignorePackageName : entityOption.ignorePackageNameList) {
                if (clazz.getName().contains(ignorePackageName)) {
                    return true;
                }
            }
        }
        //如果用户已经指定了该实体类,则跳过
        for (Class _clazz : entityOption.entityClassMap.keySet()) {
            if (_clazz.getName().equals(clazz.getName())) {
                return true;
            }
        }
        //执行用户判断逻辑
        if (null != entityOption.ignorePredicate) {
            if (entityOption.ignorePredicate.test(clazz)) {
                return true;
            }
        }
        return false;
    }
}
